/********************************************************************/
/**************** 系统级别的方法，可能因工程改变而改变 *****************/
/********************************************************************/

import { emptyVals, defaultEmptyStr } from "@/consts";
import type {
  CommonObj,
  GetRequired,
  OptionItem,
  OptionPropsMap,
  StrNum,
} from "@/types";
import { typeOf } from "@/utils";

const defaultOptionPropsMap: GetRequired<OptionPropsMap> = {
  label: "label",
  value: "value",
  children: "children",
};

/**
 * 从级联下拉项中根据下标数组获取文本
 * @param { OptionItem[]} opts 下拉项
 * @param {number[]} inds 下标数组
 */
export function getTextFromOpts(opts: OptionItem[] = [], inds: number[] = []) {
  let text = "";
  function cycle(opts: OptionItem[], ind: number = 0) {
    const { label = "", children = [] } = opts?.[inds[ind]] || {};
    text += label;
    if (children?.length) cycle(children, ind + 1);
  }
  cycle(opts);
  return text;
}

/**
 * 获取图片的http请求路径
 * @param {string} path 图片路径
 * @returns {string}
 */
export const getImgUrl = (path: string): string => {
  return new URL(path, import.meta.url).href;
};

/**
 * 根据值(非数组)从options获取label文本
 * @param {object} options 下拉项
 * @param {string|number} val 查找依据值
 * @param {OptionPropsMap} propsMap props映射
 * @param {string} emptyChar 空字符串
 */
export function getLabelFromOptionsByLastValue(
  options: CommonObj[],
  val: StrNum,
  propsMap?: OptionPropsMap,
  emptyChar = defaultEmptyStr
) {
  const {
    label: labelKey,
    value: valueKey,
    children: childrenKey,
  } = { ...defaultOptionPropsMap, ...propsMap };
  let target: CommonObj | undefined;
  function getLabel(opts: CommonObj[]): boolean {
    return !!opts.find((item) => {
      const children = item[childrenKey];
      const value = item[valueKey];
      const isFind = value === val;
      if (isFind) {
        target = item;
      } else {
        if (children?.length) return getLabel(children);
      }
      return isFind;
    });
  }
  getLabel(options);
  return target?.[labelKey] ?? emptyChar;
}

/**
 * 根据值（数组）从options获取label文本
 * @param {object} options 下拉项
 * @param {string|number} val 查找依据值
 * @param {OptionPropsMap} propsMap props映射
 * @param {string} emptyChar 空字符串
 */
export function getLabelFromOptionsByAllValues(
  options: CommonObj[] = [],
  values: StrNum[],
  propsMap?: OptionPropsMap,
  emptyChar = defaultEmptyStr,
  joinChar = "，"
) {
  const {
    label: labelKey,
    value: valueKey,
    children: childrenKey,
  } = { ...defaultOptionPropsMap, ...propsMap };
  const labels: string[] = [];
  function getLabel(opts: CommonObj[], level = 0) {
    opts.find((item) => {
      const children = item[childrenKey];
      const value = item[valueKey];
      const label = item[labelKey];
      const isFind = value === values[level];
      if (isFind) {
        labels.push(label);
        if (children) getLabel(children, ++level);
      }
      return isFind;
    });
  }
  getLabel(options);
  return labels.join(joinChar) || emptyChar;
}

/***
 * 获取select、cascader、tree下拉项中的文本
 * @param {OptionPropsMap} propsMap 属性名映射
 */
export function getTextFromOptions(
  options: CommonObj[],
  val: StrNum | StrNum[],
  propsMap?: OptionPropsMap,
  char = defaultEmptyStr
) {
  if (emptyVals.includes(val as any)) return char;
  const t = typeOf(val);
  if (t === "Array")
    return getLabelFromOptionsByAllValues(
      options,
      val as StrNum[],
      propsMap,
      char,
      ""
    );
  if (["String", "Number"].includes(t))
    return getLabelFromOptionsByLastValue(
      options,
      val as StrNum,
      propsMap,
      char
    );
  throw new Error(`暂未处理此种情况：${t}`);
}
